/*
 * Copyright (c) 2017. Visionet and/or its affiliates. All right reserved.
 * VISIONET PROPRIETARY/CONFIDENTIAL.
 */
package com.visionet.security.filter;

import java.io.IOException;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

import com.visionet.jumper.core.common.Message;
import com.visionet.jumper.core.exception.runtime.FrameworkException;
import com.visionet.jumper.utils.JsonUtils;
import com.visionet.security.base.enums.SecurityMessage;
import com.visionet.security.domain.dto.LoginUserDTO;
import com.visionet.security.utils.WebUtils;

import org.apache.shiro.authc.*;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authc.AuthenticatingFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author TC.Ubuntu
 * @since 2017/2/8.
 */
public class RestAuthenticationFilter extends AuthenticatingFilter {
	
	private final Logger logger = LoggerFactory.getLogger(this.getClass());

	protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) {
		try {
			LoginUserDTO loginUser = JsonUtils.toObject(request.getInputStream(), LoginUserDTO.class);
			if(loginUser == null || loginUser.getLoginName() == null) {
				throw new FrameworkException("login info is necessary, exactly need an account name");
			}
			return createToken(loginUser.getLoginName(), loginUser.getPassword(), getRememberMe(loginUser),
					getHost(request));
		} catch (IOException e) {
			throw new FrameworkException(e.getMessage(),e);
		}
	}

	private boolean getRememberMe(LoginUserDTO loginUser) {
		return loginUser.getRememberMe() != null ? loginUser.getRememberMe() : false;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * org.apache.shiro.web.filter.AccessControlFilter#onAccessDenied(javax.
	 * servlet.ServletRequest, javax.servlet.ServletResponse)
	 */
	@Override
	protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
		if (isLoginRequest(request, response)) {
			//Login submission detected.  Attempting to execute login.
			return executeLogin(request, response);
		} else {
			//Attempting to access a path which requires authentication.  Return to the failure info.
			Message loginMsg = new Message(SecurityMessage.NOT_LOGGED_IN.getCode(),
					SecurityMessage.NOT_LOGGED_IN.getValue());
			WebUtils.writeJsonResponse(loginMsg, WebUtils.toHttp(response));
			return false;
		}
	}

	/* (non-Javadoc)
	 * @see org.apache.shiro.web.filter.AccessControlFilter#onPreHandle(javax.servlet.ServletRequest, javax.servlet.ServletResponse, java.lang.Object)
	 */
	@Override
	public boolean onPreHandle(ServletRequest request, ServletResponse response, Object mappedValue)
			throws Exception {
		boolean continueChain= super.onPreHandle(request, response, mappedValue);
		if(continueChain && isLoginRequest(request, response)){
			continueChain=false;
		}
		return continueChain;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * org.apache.shiro.web.filter.authc.AuthenticatingFilter#onLoginSuccess
	 * (org.apache.shiro.authc.AuthenticationToken,
	 * org.apache.shiro.subject.Subject, javax.servlet.ServletRequest,
	 * javax.servlet.ServletResponse)
	 */
	@Override
	protected boolean onLoginSuccess(AuthenticationToken token, Subject subject, ServletRequest request,
			ServletResponse response) throws Exception {
		logger.info("RestAuthenticationFilter -- onLoginSuccess");
		//TODO : return some useful info when login success
		return false;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * org.apache.shiro.web.filter.authc.AuthenticatingFilter#onLoginFailure
	 * (org.apache.shiro.authc.AuthenticationToken,
	 * org.apache.shiro.authc.AuthenticationException,
	 * javax.servlet.ServletRequest, javax.servlet.ServletResponse)
	 */
	@Override
	protected boolean onLoginFailure(AuthenticationToken token, AuthenticationException e,
			ServletRequest request, ServletResponse response) {
		Message loginMsg = new Message(SecurityMessage.FAILURE.getCode(), SecurityMessage.FAILURE.getValue());
		if (e instanceof UnknownAccountException) {
			loginMsg = new Message(SecurityMessage.ACCOUNT_NOT_FOUNT.getCode(),
					SecurityMessage.ACCOUNT_NOT_FOUNT.getValue());
		} else if (e instanceof IncorrectCredentialsException) {
			loginMsg = new Message(SecurityMessage.CREDENTIAL_INCORRECT.getCode(),
					SecurityMessage.CREDENTIAL_INCORRECT.getValue());
		} else if (e instanceof ExpiredCredentialsException) {
			loginMsg = new Message(SecurityMessage.CREDENTIAL_EXPIRED.getCode(),
					SecurityMessage.CREDENTIAL_EXPIRED.getValue());
		} else if (e instanceof ExcessiveAttemptsException) {
			loginMsg = new Message(SecurityMessage.EXCESSIVE_ACCESS.getCode(),
					SecurityMessage.EXCESSIVE_ACCESS.getValue());
		}
		WebUtils.writeJsonResponse(loginMsg, WebUtils.toHttp(response));
		return true;
	}

}
